#include "../include/http_server.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <thread>
#include <chrono>
#include <map>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#define CLOSE_SOCKET(sock) closesocket(sock)
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define CLOSE_SOCKET(sock) close(sock)
#endif

HttpServer::HttpServer(int port) : port_(port), running_(false), db_manager_(nullptr), user_manager_(nullptr), search_engine_(nullptr), ai_integration_(nullptr) {
#ifdef _WIN32
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}

HttpServer::~HttpServer() {
    stop();
#ifdef _WIN32
    WSACleanup();
#endif
}

bool HttpServer::start() {
    if (running_) {
        return false;
    }

    SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == INVALID_SOCKET) {
        std::cerr << "Failed to create socket" << std::endl;
        return false;
    }

    int opt = 1;
    if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
        std::cerr << "Failed to set socket options" << std::endl;
        CLOSE_SOCKET(server_socket);
        return false;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port_);

    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to bind socket" << std::endl;
        CLOSE_SOCKET(server_socket);
        return false;
    }

    if (listen(server_socket, 10) < 0) {
        std::cerr << "Failed to listen on socket" << std::endl;
        CLOSE_SOCKET(server_socket);
        return false;
    }

    running_ = true;
    std::cout << "Server started on port " << port_ << std::endl;

    // Start accepting connections in a separate thread
    std::thread accept_thread([this, server_socket]() {
        while (running_) {
            struct sockaddr_in client_addr;
            socklen_t client_len = sizeof(client_addr);
            
            SOCKET client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_len);
            if (client_socket == INVALID_SOCKET) {
                if (running_) {
                    std::cerr << "Failed to accept client connection" << std::endl;
                }
                continue;
            }

            // Handle each client in a separate thread
            std::thread client_thread([this, client_socket]() {
                char buffer[4096];
                int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
                
                if (bytes_received > 0) {
                    buffer[bytes_received] = '\0';
                    std::string request(buffer);
                    
                    // Parse HTTP request
                    std::string method, path, headers_str, body;
                    
                    
                    // Parse request line
                    size_t method_end = request.find(' ');
                    size_t path_end = request.find(' ', method_end + 1);
                    method = request.substr(0, method_end);
                    path = request.substr(method_end + 1, path_end - method_end - 1);
                    
                    
                    // Parse headers and body
                    size_t header_end = request.find("\r\n\r\n");
                    if (header_end != std::string::npos) {
                        headers_str = request.substr(path_end + 1, header_end - path_end - 1);
                        body = request.substr(header_end + 4);
                    }
                    
                    
                    // Parse headers
                    std::map<std::string, std::string> headers;
                    std::istringstream header_stream(headers_str);
                    std::string line;
                    while (std::getline(header_stream, line)) {
                        size_t colon_pos = line.find(':');
                        if (colon_pos != std::string::npos) {
                            std::string key = line.substr(0, colon_pos);
                            std::string value = line.substr(colon_pos + 2); // +2 skip colon and space
                            headers[key] = value;
                        }
                    }

                    // Ensure full body is read based on Content-Length
                    auto itCL = headers.find("Content-Length");
                    if (itCL != headers.end()) {
                        int content_length = 0;
                        try { content_length = std::stoi(itCL->second); } catch (...) { content_length = 0; }
                        while ((int)body.size() < content_length) {
                            char more[4096];
                            int more_received = recv(client_socket, more, sizeof(more), 0);
                            if (more_received <= 0) {
                                break;
                            }
                            body.append(more, more_received);
                        }
                        if ((int)body.size() > content_length) {
                            body.resize(content_length);
                        }
                    }
                    
                    // Handle request
                    std::string response = handleRequest(method, path, headers, body);
                    
                    // Send response
                    send(client_socket, response.c_str(), response.size(), 0);
                }
                
                CLOSE_SOCKET(client_socket);
            });
            client_thread.detach();
        }
        
        CLOSE_SOCKET(server_socket);
    });
    accept_thread.detach();

    return true;
}

void HttpServer::stop() {
    running_ = false;
    // Wait for threads to finish
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Server stopped" << std::endl;
}

void HttpServer::setDatabaseManager(DBManager* db_manager) {
    db_manager_ = db_manager;
}

void HttpServer::setUserManager(UserManager* user_manager) {
    user_manager_ = user_manager;
}

void HttpServer::setSearchEngine(SearchEngine* search_engine) {
    search_engine_ = search_engine;
}

void HttpServer::setAIIntegration(AIIntegration* ai_integration) {
    ai_integration_ = ai_integration;
}

std::string HttpServer::handleRequest(const std::string& method, const std::string& path, 
                                     const std::map<std::string, std::string>& headers,
                                     const std::string& body) {
    // Basic request logging
    std::cout << "[HTTP] " << method << " " << path << std::endl;

    // Handle CORS preflight requests
    if (method == "OPTIONS") {
        std::string response = "HTTP/1.1 204 No Content\r\n";
        response += "Access-Control-Allow-Origin: *\r\n";
        response += "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n";
        response += "Access-Control-Allow-Headers: Content-Type\r\n";
        response += "Access-Control-Max-Age: 86400\r\n";
        response += "Content-Length: 0\r\n";
        response += "Server: C++ HTTP Server\r\n";
        response += "\r\n";
        return response;
    }

    // API routing
    if (path == "/api/register" && method == "POST") {
        return handleUserRegister(body);
    }
    else if (path == "/api/user/register" && method == "POST") {
        return handleUserRegister(body);
    }
    else if (path == "/api/login" && method == "POST") {
        return handleUserLogin(body);
    }
    else if (path == "/api/user/login" && method == "POST") {
        return handleUserLogin(body);
    }
    else if (path.find("/api/user/info/") == 0 && method == "GET") {
        std::string user_id = path.substr(15);
        return handleGetUserInfo(user_id);
    }
    else if (path.find("/api/user/balance/") == 0 && method == "GET") {
        std::string user_id = path.substr(18);
        return handleGetUserBalance(user_id);
    }
    else if (path.find("/api/search") == 0 && method == "GET") {
        // Extract query parameters
        size_t query_pos = path.find("?query=");
        std::string query = "";
        if (query_pos != std::string::npos) {
            query = path.substr(query_pos + 7);
        }
        return handleSearch(query);
    }
    else if (path == "/api/keyword/weight" && method == "POST") {
        return handleSetKeywordWeight(body);
    }
    else if (path == "/api/ai/query" && method == "POST") {
        return handleAIQuery(body);
    }
    else if (path.find("/api/keyword/list/") == 0 && method == "GET") {
        std::string user_id = path.substr(18);
        return handleGetKeywordList(user_id);
    }
    else if (method == "GET") {
        // Static file handling
        if (path == "/") {
            // Try multiple possible paths
            std::string indexPath = "src/frontend/index.html";
            std::ifstream testFile(indexPath);
            if (!testFile) {
                // If not found, try relative path
                indexPath = "../src/frontend/index.html";
                testFile.open(indexPath);
                if (!testFile) {
                    // If still not found, try one level up
                    indexPath = "../../src/frontend/index.html";
                }
            }
            return serveStaticFile(indexPath);
        } else {
            // Try multiple possible paths
            std::string filePath = "src/frontend" + path;
            std::ifstream testFile(filePath);
            if (!testFile) {
                filePath = "../src/frontend" + path;
                testFile.open(filePath);
                if (!testFile) {
                    filePath = "../../src/frontend" + path;
                }
            }
            return serveStaticFile(filePath);
        }
    }
    
    // 404 response
    return createResponse(404, "text/plain", "Not Found");
}

// Implement API handler functions
std::string HttpServer::handleUserRegister(const std::string& body) {
    auto data = parseJson(body);
    
    if (data.find("username") == data.end() || data.find("password") == data.end()) {
        return createResponse(400, "application/json", "{\"error\": \"Missing required parameters\"}");
    }
    
    if (user_manager_->registerUser(data["username"], data["password"], 
                                    data.find("phone") != data.end() ? data["phone"] : "",
                                    data.find("email") != data.end() ? data["email"] : "")) {
        return createResponse(200, "application/json", "{\"success\": true, \"message\": \"Registration successful\"}");
    } else {
        return createResponse(500, "application/json", "{\"error\": \"Registration failed\"}");
    }
}

std::string HttpServer::handleUserLogin(const std::string& body) {
    std::cout << "Login request body: " << body << std::endl;
    auto data = parseJson(body);
    std::cout << "Parsed JSON data - username: " << (data.find("username") != data.end() ? data["username"] : "NOT_FOUND") 
              << ", password: " << (data.find("password") != data.end() ? "PRESENT" : "NOT_FOUND") << std::endl;
    
    if (data.find("username") == data.end() || data.find("password") == data.end()) {
        return createResponse(400, "application/json", "{\"error\": \"Missing required parameters\"}");
    }
    
    int user_id = 0;
    if (user_manager_->loginUser(data["username"], data["password"], user_id)) {
        std::string session_id = createSession(user_id);
        std::string json_response = "{\"success\": true, \"user_id\": " + std::to_string(user_id) + ", \"session_id\": \"" + session_id + "\"}";
        auto response = createResponse(200, "application/json", json_response);
        response += "Set-Cookie: session=" + session_id + "; Path=/; HttpOnly\r\n";
        return response;
    } else {
        return createResponse(401, "application/json", "{\"error\": \"Invalid username or password\"}");
    }
}

std::string HttpServer::handleGetUserInfo(const std::string& user_id) {
    std::map<std::string, std::string> user_info;
    if (user_manager_->getUserInfo(std::stoi(user_id), user_info)) {
        return createResponse(200, "application/json", generateJson(user_info));
    } else {
        return createResponse(404, "application/json", "{\"error\": \"User not found\"}");
    }
}

std::string HttpServer::handleGetUserBalance(const std::string& user_id) {
    // Get user info first to extract balance
    std::map<std::string, std::string> user_info;
    if (user_manager_->getUserInfo(std::stoi(user_id), user_info)) {
        double balance = 0.0;
        if (user_info.find("balance") != user_info.end()) {
            balance = std::stod(user_info["balance"]);
        }
        return createResponse(200, "application/json", "{\"balance\": " + std::to_string(balance) + "}");
    } else {
        return createResponse(404, "application/json", "{\"error\": \"User not found\"}");
    }
}

std::string HttpServer::handleSearch(const std::string& query) {
    if (!search_engine_) {
        return createResponse(500, "application/json", "{\"error\": \"Search engine not available\"}");
    }
    
    auto results = search_engine_->search(query);
    std::string json_results = "[";
    for (size_t i = 0; i < results.size(); ++i) {
        if (i > 0) json_results += ",";
        json_results += "{\"title\": \"" + results[i].title + "\", \"url\": \"" + results[i].url + "\", \"snippet\": \"" + results[i].description + "\"}";
    }
    json_results += "]";
    
    return createResponse(200, "application/json", json_results);
}

std::string HttpServer::handleSetKeywordWeight(const std::string& body) {
    auto data = parseJson(body);
    
    if (data.find("user_id") == data.end() || data.find("keyword") == data.end() || data.find("weight") == data.end()) {
        return createResponse(400, "application/json", "{\"error\": \"Missing required parameters\"}");
    }
    
    int user_id = std::stoi(data["user_id"]);
    std::string keyword = data["keyword"];
    double weight = std::stod(data["weight"]);
    
    if (db_manager_->setKeywordWeight(user_id, keyword, weight)) {
        return createResponse(200, "application/json", "{\"success\": true}");
    } else {
        return createResponse(500, "application/json", "{\"error\": \"Failed to set keyword weight\"}");
    }
}

std::string HttpServer::handleAIQuery(const std::string& body) {
    
    std::string query;
    auto data = parseJson(body);
    if (data.find("query") != data.end()) {
        query = data["query"];
    } else {
        size_t key_pos = body.find("\"query\"");
        if (key_pos != std::string::npos) {
            size_t colon_pos = body.find(":", key_pos);
            if (colon_pos != std::string::npos) {
                size_t val_start_quote = body.find("\"", colon_pos);
                if (val_start_quote != std::string::npos) {
                    size_t val_end_quote = body.find("\"", val_start_quote + 1);
                    if (val_end_quote != std::string::npos) {
                        query = body.substr(val_start_quote + 1, val_end_quote - (val_start_quote + 1));
                    }
                }
            }
        }
    }
    if (query.empty()) {
        return createResponse(400, "application/json", "{\"error\": \"Missing query parameter\"}");
    }
    if (!ai_integration_) {
        return createResponse(500, "application/json", "{\"error\": \"AI integration not available\"}");
    }
    AIResponse response = ai_integration_->query(query);
    auto escapeJSONString = [](const std::string& s) {
        std::string r; r.reserve(s.size());
        for (char c : s) {
            switch (c) {
                case '"': r += "\\\""; break;
                case '\\': r += "\\\\"; break;
                case '\n': r += "\\n"; break;
                case '\r': r += "\\r"; break;
                case '\t': r += "\\t"; break;
                default: r += c; break;
            }
        }
        return r;
    };
    if (response.success) {
        return createResponse(200, "application/json", "{\"answer\": \"" + escapeJSONString(response.content) + "\"}");
    } else {
        return createResponse(500, "application/json", "{\"error\": \"" + escapeJSONString(response.error_message) + "\"}");
    }
}

std::string HttpServer::handleGetKeywordList(const std::string& user_id) {
    auto keywords = db_manager_->getKeywordsByUser(std::stoi(user_id));
    std::string json_keywords = "[";
    bool first = true;
    for (const auto& keyword_pair : keywords) {
        if (!first) json_keywords += ",";
        json_keywords += "{\"keyword\": \"" + keyword_pair.first + "\", \"weight\": " + std::to_string(keyword_pair.second) + "}";
        first = false;
    }
    json_keywords += "]";
    
    return createResponse(200, "application/json", json_keywords);
}

std::string HttpServer::serveStaticFile(const std::string& file_path) {
    std::ifstream file(file_path);
    if (!file.is_open()) {
        return createResponse(404, "text/plain", "File not found");
    }
    
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    
    // Determine content type based on file extension
    std::string content_type = "text/html";
    if (file_path.find(".css") != std::string::npos) {
        content_type = "text/css";
    } else if (file_path.find(".js") != std::string::npos) {
        content_type = "application/javascript";
    } else if (file_path.find(".json") != std::string::npos) {
        content_type = "application/json";
    }
    
    return createResponse(200, content_type, content);
}

std::string HttpServer::createResponse(int status_code, const std::string& content_type, const std::string& content) {
    std::string response = "HTTP/1.1 " + std::to_string(status_code);
    
    switch (status_code) {
        case 200: response += " OK"; break;
        case 204: response += " No Content"; break;
        case 400: response += " Bad Request"; break;
        case 401: response += " Unauthorized"; break;
        case 404: response += " Not Found"; break;
        case 500: response += " Internal Server Error"; break;
        default: response += " Unknown"; break;
    }
    
    response += "\r\n";
    response += "Content-Type: " + content_type + "\r\n";
    response += "Content-Length: " + std::to_string(content.length()) + "\r\n";
    response += "Access-Control-Allow-Origin: *\r\n";
    response += "Server: C++ HTTP Server\r\n";
    response += "\r\n";
    response += content;
    
    return response;
}

std::map<std::string, std::string> HttpServer::parseJson(const std::string& json) {
    std::map<std::string, std::string> result;
    
    // Simple JSON parsing (for basic key-value pairs)
    std::string json_copy = json;
    
    // Remove braces
    if (!json_copy.empty() && json_copy.front() == '{') json_copy.erase(0, 1);
    if (!json_copy.empty() && json_copy.back() == '}') json_copy.pop_back();
    
    // Split by commas
    std::stringstream ss(json_copy);
    std::string item;
    
    while (std::getline(ss, item, ',')) {
        // Trim whitespace
        item.erase(0, item.find_first_not_of(" \t\n\r"));
        item.erase(item.find_last_not_of(" \t\n\r") + 1);
        
        // Find colon
        size_t colon_pos = item.find(':');
        if (colon_pos != std::string::npos) {
            std::string key = item.substr(0, colon_pos);
            std::string value = item.substr(colon_pos + 1);
            
            // Remove quotes and whitespace from key
            key.erase(0, key.find_first_not_of(" \t\n\r"));
            key.erase(key.find_last_not_of(" \t\n\r") + 1);
            if (!key.empty() && key.front() == '"') key.erase(0, 1);
            if (!key.empty() && key.back() == '"') key.pop_back();
            
            // Remove quotes and whitespace from value
            value.erase(0, value.find_first_not_of(" \t\n\r"));
            value.erase(value.find_last_not_of(" \t\n\r") + 1);
            if (!value.empty() && value.front() == '"') value.erase(0, 1);
            if (!value.empty() && value.back() == '"') value.pop_back();
            
            if (!key.empty()) {
                result[key] = value;
            }
        }
    }
    
    return result;
}

std::string HttpServer::generateJson(const std::map<std::string, std::string>& data) {
    std::string json = "{";
    bool first = true;
    
    for (const auto& pair : data) {
        if (!first) json += ",";
        json += "\"" + pair.first + "\": \"" + pair.second + "\"";
        first = false;
    }
    
    json += "}";
    return json;
}

std::string HttpServer::createSession(int user_id) {
    // Simple session creation (in production, use proper session management)
    return "session_" + std::to_string(user_id) + "_" + std::to_string(std::time(nullptr));
}
